struct service
{
  char *sv_name;
  char sv_useTCP;
  int sv_sock;
  int (*sv_func) (int);
};
struct service svent[] = {
  {"echo", TCP_SERV, NOSOCK, TCPechod},
  {"chargen", TCP_SERV, NOSOCK, TCPchargend},
  {"daytime", TCP_SERV, NOSOCK, TCPdaytimed},
  {"time", TCP_SERV, NOSOCK, TCPtimed},
  {0, 0, 0, 0},
};

int
main (int argc, char *argv[])
{
  struct service *psv,		/* service table pointer */
   *fd2sv[NOFILE];		/* map fd to service pointer */
  int fd, nfds;
  fd_set afds, rfds;		/* readable file descriptors */
  nfds = 0;
  FD_ZERO (&afds);
  for (psv = &svent[0]; psv->sv_name; ++psv)
    {
      if (psv->sv_useTCP)
	psv->sv_sock = passiveTCP (psv->sv_name, QLEN);
      else
	psv->sv_sock = passiveUDP (psv->sv_name);
      fd2sv[psv->sv_sock] = psv;
      nfds = MAX (psv->sv_sock + 1, nfds);
      FD_SET (psv->sv_sock, &afds);
    }

  (void) signal (SIGCHLD, reaper);
  while (1)
    {
      memcpy (&rfds, &afds, sizeof (rfds));
      if (select
	  (nfds, &rfds, (fd_set *) 0, (fd_set *) 0, (struct timeval *) 0) < 0)
	{
	  if (errno == EINTR)
	    continue;
	  errexit ("select error: %s\n", strerror (errno));
	}
      for (fd = 0; fd < nfds; ++fd)
	{
	  if (FD_ISSET (fd, &rfds))
	    {
	      psv = fd2sv[fd];
	      if (psv->sv_useTCP)
		doTCP (psv);
	      else
		psv->sv_func (psv->sv_sock);
	    }
	}
    }
}

    /* doTCP() - handle a TCP service connection request */
void
doTCP (struct service *psv)
{
  /* the request from address */
  struct sockaddr_in fsin;
  /* from-address length */
  int alen;
  int fd, ssock;
  alen = sizeof (fsin);
  ssock = accept (psv->sv_sock, (struct sockaddr *) &fsin, &alen);
  if (ssock < 0)
    errexit ("accept: %s\n", strerror (errno));
  switch (fork ())
    {
    case 0:
      break;
    case -1:
      errexit ("fork: %s\n", strerror (errno));
    default:
      (void) close (ssock);
      /* parent */
      return;
    }
  /* child */
  for (fd = NOFILE; fd >= 0; --fd)
    if (fd != ssock)
      (void) close (fd);
  exit (psv->sv_func (ssock));
}

    /* reaper() - clean up zombie children */
void
reaper (int sig)
{
  int status;
  while (wait3 (&status, WNOHANG, (struct rusage *) 0) >= 0)
    /* empty */ ;
}
